
# step 11 Run non-linear dimensional reduction (UMAP/tSNE)
# If you haven't installed UMAP, you can do so via reticulate::py_install(packages = 'umap-learn')
pbmc <- RunUMAP(pbmc, dims = 1:10)

# note that you can set `label = TRUE` or use the LabelClusters function to help label
# individual clusters
DimPlot(pbmc, reduction = "umap")

# saveRDS(pbmc, file = "../output/pbmc_tutorial.rds")




$ find . | grep "R$" | xargs grep -in RunUMAP --color=auto 2>/dev/null


(1) options("Seurat.warn.umap.uwot")
./seurat-4.1.0/R/zzz.R:12:#'   for \code{\link{RunUMAP}} changing from Python UMAP via reticulate to UWOT}
R内的全局环境变量：为了保证有一个提示在每一个R session 只提示一次。


#'   \item{\code{Seurat.warn.umap.uwot}}{Show warning about the default backend
#'   for \code{\link{RunUMAP}} changing from Python UMAP via reticulate to UWOT}
  Seurat.warn.umap.uwot = TRUE,

> options("Seurat.warn.umap.uwot")
$Seurat.warn.umap.uwot
[1] TRUE





() RunUMAP() 泛型函数
./seurat-4.1.0/R/generics.R:538:RunUMAP <- function(object, ...) {



需要先安装py包: pip install umap-learn
github: https://github.com/lmcinnes/umap
paper title: Uniform Manifold Approximation and Projection for Dimension Reduction
paper PDF: https://arxiv.org/abs/1802.03426 UMAP

#' Run UMAP
#'
#' Runs the Uniform Manifold Approximation and Projection (UMAP) dimensional
#' reduction technique. To run, you must first install the umap-learn python
#' package (e.g. via \code{pip install umap-learn}). Details on this package can be
#' found here: \url{https://github.com/lmcinnes/umap}. For a more in depth
#' discussion of the mathematics underlying UMAP, see the ArXiv paper here:
#' \url{https://arxiv.org/abs/1802.03426}.
#'
#' @param object An object
#' @param ... Arguments passed to other methods and UMAP
#'
#' @return Returns a Seurat object containing a UMAP representation
#'
#' @references McInnes, L, Healy, J, UMAP: Uniform Manifold Approximation and
#' Projection for Dimension Reduction, ArXiv e-prints 1802.03426, 2018
#'
#' @export
#'
#' @examples
#' \dontrun{
#' data("pbmc_small")
#' pbmc_small
#' # Run UMAP map on first 5 PCs
#' pbmc_small <- RunUMAP(object = pbmc_small, dims = 1:5)
#' # Plot results
#' DimPlot(object = pbmc_small, reduction = 'umap')
#' }
#'
#' @rdname RunUMAP
#' @export RunUMAP
#'
RunUMAP <- function(object, ...) {
  UseMethod(generic = 'RunUMAP', object = object)
}









() RunUMAP.Seurat() 参数解释
./seurat-4.1.0/R/dimensional_reduction.R:1659:RunUMAP.Seurat <- function(

> ?uwot::umap
Some of the following help text is lifted verbatim from the Python reference implementation at https://github.com/lmcinnes/umap.


#' @param reduction.model \code{DimReduc} object that contains the umap model
参数 reduction.model 对象包含 umap 模型。默认为空。

#' @param dims Which dimensions to use as input features, used only if
#' \code{features} is NULL 
如果 features 为NULLL，则使用 dims 选定的维度作为输入。

#' @param reduction Which dimensional reduction (PCA or ICA) to use for the
#' UMAP input. Default is PCA
参数 reduction 规定了UMAP的输入(PCA or ICA，默认是PCA)。

#' @param features If set, run UMAP on this subset of features (instead of running on a
#' set of reduced dimensions). Not set (NULL) by default; \code{dims} must be NULL to run
#' on features
参数 features 默认空。
如果非空，则使用这几个特征运行UMAP，而不是使用几个PCA维度。


#' @param graph Name of graph on which to run UMAP
参数 graph: 在这上面运行 UMAP。 默认为空。

#' @param assay Assay to pull data for when using \code{features}, or assay used to construct Graph
#' if running UMAP on a Graph
参数 assay，使用 features 时从哪里获取数据？或者构架 Graph 时使用哪个 assay?

#' @param nn.name Name of knn output on which to run UMAP
运行 UMAP 时使用 knn 输出的名字。 


#' @param slot The slot used to pull data for when using \code{features}. data slot is by default.
参数 slot="data": 使用 features 时从哪个slot 获取数据。


#' @param umap.method UMAP implementation to run. Can be
#' \describe{
#'   \item{\code{uwot}:}{Runs umap via the uwot R package}
#'   \item{\code{uwot-learn}:}{Runs umap via the uwot R package and return the learned umap model}
#'   \item{\code{umap-learn}:}{Run the Seurat wrapper of the python umap-learn package}
#' }
参数 umap.method="uwot": 
- "uwot": 使用R包uwot运行 umap。 默认。
- "uwot-learn": 使用R包uwot运行 umap，并返回 umap 模型。//？
- "umap-learn": 运行 umap-learn py包的Seurat 包装函数。


#' @param n.neighbors This determines the number of neighboring points used in
#' local approximations of manifold structure. Larger values will result in more
#' global structure being preserved at the loss of detailed local structure. In
#' general this parameter should often be in the range 5 to 50.
参数 n.neighbors: 局部近似时使用的紧邻点个数。越大越能保留全局结构。通常 5-50 。默认 30。


#' @param n.components The dimension of the space to embed into. 
返回的维度个数，默认2.


#' @param metric metric: This determines the choice of metric used to measure
#' distance in the input space. A wide variety of metrics are already coded, and
#' a user defined function can be passed as long as it has been JITd by numba.
metric: 距离: 支持很多距离，也可以传入 numba 支持的可以JIT的函数。


#' @param n.epochs the number of training epochs to be used in optimizing the low dimensional
#' embedding. Larger values result in more accurate embeddings. If NULL is specified, a value will
#' be selected based on the size of the input dataset (200 for large datasets, 500 for small).
bug: 文档拼写错误: he --> the
在低维训练的次数。越大则嵌入越精确。如果为空，则大数据集 200，小数据集 500.


#' @param learning.rate The initial learning rate for the embedding optimization.
嵌入初始的学习率。

#' @param min.dist This controls how tightly the embedding is allowed compress points together.
#' Larger values ensure embedded points are more evenly distributed, while smaller values allow the
#' algorithm to optimise more accurately with regard to local structure. Sensible values are in
#' the range 0.001 to 0.5.
min.dist: 最小距离，控制着压缩点时多远的合并。
大值保证嵌入点更均匀，小值保证局部结构更精确。合理范围是 0.001-0.5，默认0.3


#' @param spread The effective scale of embedded points. In combination with min.dist this
#' determines how clustered/clumped the embedded points are.
spread: 嵌入点时的缩放。 和 min.dist 结合使用，控制着点的聚合/集合分布。


#' @param set.op.mix.ratio Interpolate between (fuzzy) union and intersection as the set operation
#' used to combine local fuzzy simplicial sets to obtain a global fuzzy simplicial sets. Both fuzzy
#' set operations use the product t-norm. The value of this parameter should be between 0.0 and
#' 1.0; a value of 1.0 will use a pure fuzzy union, while 0.0 will use a pure fuzzy intersection.
set.op.mix.ratio: 在(模糊)并与交之间插值，作为集合运算，用于组合局部模糊单纯集，得到全局模糊单纯集。
两个模糊集合操作都使用乘积t范数。
该参数的值应该在0.0到1.0之间; 1.0的值将使用纯模糊联合，而0.0将使用纯模糊交集。


#' @param local.connectivity The local connectivity required - i.e. the number of nearest neighbors
#' that should be assumed to be connected at a local level. The higher this value the more connected
#' the manifold becomes locally. In practice this should be not more than the local intrinsic
#' dimension of the manifold.
local.connectivity: 需要的本地连通性，即假定在局部连接的最近邻居的数量。
这个值越高，表示流形的局部连接程度越高。实际上，它不应该大于流形的局部内维。 



#' @param repulsion.strength Weighting applied to negative samples in low dimensional embedding
#' optimization. Values higher than one will result in greater weight being given to negative
#' samples.
repulsion.strength: 低维嵌入优化时，负样本之间的权重。
大于1将会导致给负样本更大的权重。


#' @param negative.sample.rate The number of negative samples to select per positive sample in the
#' optimization process. Increasing this value will result in greater repulsive force being applied,
#' greater optimization cost, but slightly more accuracy.
negative.sample.rate: 优化过程中，每个正样本要选择几个负样本。
增加这个值会导致排斥力更大，优化代价更大，但是精确度略微增加。


#' @param a More specific parameters controlling the embedding. If NULL, these values are set
#' automatically as determined by min. dist and spread. Parameter of differentiable approximation of
#' right adjoint functor.
参数 a: 控制嵌入的具体参数。如果为空，则自动设置为 min(min.dist, spread).
右伴随函子的可微逼近参数。


#' @param b More specific parameters controlling the embedding. If NULL, these values are set
#' automatically as determined by min. dist and spread. Parameter of differentiable approximation of
#' right adjoint functor.
参数 b: 控制嵌入的具体参数。如果为空，则自动设置为 min(min.dist, spread).
右伴随函子的可微逼近参数。


#' @param uwot.sgd Set \code{uwot::umap(fast_sgd = TRUE)}; see \code{\link[uwot]{umap}} for more details
>?uwot::umap
默认 fast_sgd = FALSE,

fast_sgd: 默认F。如果设置为T，则以下参数组合被设置：
If TRUE, then the following combination of parameters is set: 
	pcg_rand = TRUE, n_sgd_threads = "auto" and approx_pow = TRUE. 
The default is FALSE. 
如果使用T，用户自定义的这三个参数将会失效。
If fast_sgd = TRUE, then user-supplied values of pcg_rand, n_sgd_threads, and approx_pow are ignored.

设置为T会加快随机优化过程，但是可能给出不精确的嵌入，即使固定随机数也可能不能精确重复。
Setting this to TRUE will speed up the stochastic optimization phase, but give a potentially less 
accurate embedding, and which will not be exactly reproducible even with a fixed seed. 

对于可视化，T能给出完美效果。
For visualization, fast_sgd = TRUE will give perfectly good results. 

对于更一般的降维，最好使用F。
For more generic dimensionality reduction, it's safer to leave fast_sgd = FALSE. 





#' @param metric.kwds A dictionary of arguments to pass on to the metric, such as the p value for
#' Minkowski distance. If NULL then no arguments are passed on.


#' @param angular.rp.forest Whether to use an angular random projection forest to initialise the
#' approximate nearest neighbor search. This can be faster, but is mostly on useful for metric that
#' use an angular style distance such as cosine, correlation etc. In the case of those metrics
#' angular forests will be chosen automatically.

#' @param densmap Whether to use the density-augmented objective of densMAP.
#' Turning on this option generates an embedding where the local densities
#' are encouraged to be correlated with those in the original space.
#' Parameters below with the prefix ‘dens’ further control the behavior
#' of this extension. Default is FALSE. Only compatible with 'umap-learn' method
#' and version of umap-learn >= 0.5.0

#' @param densmap.kwds A dictionary of arguments to pass on to the densMAP optimization.
#' @param dens.lambda Specific parameter which controls the regularization weight
#' of the density correlation term in densMAP. Higher values prioritize density
#' preservation over the UMAP objective, and vice versa for values closer to zero.
#' Setting this parameter to zero is equivalent to running the original UMAP algorithm.
#' Default value is 2.
#' @param dens.frac Specific parameter which controls the fraction of epochs
#' (between 0 and 1) where the density-augmented objective is used in densMAP.
#' The first (1 - dens_frac) fraction of epochs optimize the original UMAP
#' objective before introducing the density correlation term. Default is 0.3.
#' @param dens.var.shift Specific parameter which specifies a small constant
#' added to the variance of local radii in the embedding when calculating
#' the density correlation objective to prevent numerical instability from
#' dividing by a small number. Default is 0.1.
#' @param reduction.name Name to store dimensional reduction under in the Seurat object
#' @param reduction.key dimensional reduction key, specifies the string before
#' the number for the dimension names. UMAP by default
#' @param return.model whether UMAP will return the uwot model
默认不返回，返回了放到哪？

#' @param seed.use Set a random seed. By default, sets the seed to 42. Setting
#' NULL will not set a seed
随机数种子默认是 42.


#' @param verbose Controls verbosity
#'
#' @rdname RunUMAP
#' @concept dimensional_reduction
#' @export
#' @method RunUMAP Seurat
#'
RunUMAP.Seurat <- function(
  object,
  dims = NULL,
  reduction = 'pca',
  features = NULL,
  graph = NULL,
  assay = DefaultAssay(object = object),
  nn.name = NULL,
  slot = 'data',
  umap.method = 'uwot',
  reduction.model = NULL,
  return.model = FALSE,
  n.neighbors = 30L,
  n.components = 2L,
  metric = 'cosine',
  n.epochs = NULL,
  learning.rate = 1,
  min.dist = 0.3,
  spread = 1,
  set.op.mix.ratio = 1,
  local.connectivity = 1L,
  repulsion.strength = 1,
  negative.sample.rate = 5L,
  a = NULL,
  b = NULL,
  uwot.sgd = FALSE,
  seed.use = 42L,
  metric.kwds = NULL,
  angular.rp.forest = FALSE,
  densmap = FALSE,
  dens.lambda = 2,
  dens.frac = 0.3,
  dens.var.shift = 0.1,
  verbose = TRUE,
  reduction.name = 'umap',
  reduction.key = 'UMAP_',
  ...
) {
  # 检查其他参数
  CheckDots(...)

  # (A1)输入最多是一个: dims, features, or graph，否则报错。
  # (B1)统计非空元素个数，并求和。
  if (sum(c(is.null(x = dims), is.null(x = features), is.null(x = graph))) < 2) {
      stop("Please specify only one of the following arguments: dims, features, or graph")
  }

  # (B2) 如果 features 非空(默认不走这里)
  if (!is.null(x = features)) {
  	# 使用 pbmc@assays$RNA@data 数据的 这几个基因，转置后，基因为列。
    data.use <- as.matrix(x = t(x = GetAssayData(object = object, slot = slot, assay = assay)[features, , drop = FALSE]))
    # 如果列数小于 要返回的维数，则报错
    if (ncol(x = data.use) < n.components) {
      stop(
        "Please provide as many or more features than n.components: ",
        length(x = features),
        " features provided, ",
        n.components,
        " UMAP components requested",
        call. = FALSE
      )
    }

  # (B3) 如果 dims 非空(默认)
  } else if (!is.null(x = dims)) {
  	# 则选择 obj[["pca"]] 的这几列
    data.use <- Embeddings(object[[reduction]])[, dims]
    # assay 肯定也是 obj[["pca"]]
    assay <- DefaultAssay(object = object[[reduction]])
    # 如果 dims 长度小于 要输出的维度数，则报错
    if (length(x = dims) < n.components) {
      stop(
        "Please provide as many or more dims than n.components: ",
        length(x = dims),
        " dims provided, ",
        n.components,
        " UMAP components requested",
        call. = FALSE
      )
    }

  # (B4) 如果 nn.name 非空(默认不走这里)
  # names(pbmc@neighbors) #NULL
  }  else if (!is.null(x = nn.name)) {
  	# 如果 obj[[nn.name]] 不是 “Neighbor” 的实例，则报错
    if (!inherits(x = object[[nn.name]], what = "Neighbor")) {
      stop(
        "Please specify a Neighbor object name, ",
        "instead of the name of a ",
        class(object[[nn.name]]),
        " object",
        call. = FALSE
      )
    }
    data.use <- object[[nn.name]]

  # (B5) 如果 graph 非空 （默认不走这里）
  # class(pbmc@graphs$RNA_nn) #[1] "Graph"
  } else if (!is.null(x = graph)) {
  	# 如果不是 Graph 类的对象，则报错
    if (!inherits(x = object[[graph]], what = "Graph")) {
      stop(
        "Please specify a Graph object name, ",
        "instead of the name of a ",
        class(object[[graph]]),
        " object",
        call. = FALSE
      )
    }
    data.use <- object[[graph]]
  
  # (B6)只能提供以上几个输入: dims, features, or graph
  } else {
    stop("Please specify one of dims, features, or graph")
  }


  # (A2) 填充 obj[['umap']]，默认调用的是 RunUMAP.default()
  object[[reduction.name]] <- RunUMAP(
    object = data.use,
    reduction.model = reduction.model,
    return.model = return.model,
    assay = assay,
    umap.method = umap.method,
    n.neighbors = n.neighbors,
    n.components = n.components,
    metric = metric,
    n.epochs = n.epochs,
    learning.rate = learning.rate,
    min.dist = min.dist,
    spread = spread,
    set.op.mix.ratio = set.op.mix.ratio,
    local.connectivity = local.connectivity,
    repulsion.strength = repulsion.strength,
    negative.sample.rate = negative.sample.rate,
    a = a,
    b = b,
    uwot.sgd = uwot.sgd,
    seed.use = seed.use,
    metric.kwds = metric.kwds,
    angular.rp.forest = angular.rp.forest,
    densmap = densmap,
    dens.lambda = dens.lambda,
    dens.frac = dens.frac,
    dens.var.shift = dens.var.shift,
    reduction.key = reduction.key,
    verbose = verbose
  )

  # 记录日志
  object <- LogSeuratCommand(object = object)
  return(object)
}







()
./seurat-4.1.0/R/dimensional_reduction.R:1193:RunUMAP.default <- function(

尝试单独运行 umap，重点关注输入和输出是什么？



#' @importFrom reticulate py_module_available py_set_seed import
#' @importFrom uwot umap umap_transform
#' @importFrom future nbrOfWorkers
#'
#' @rdname RunUMAP
#' @concept dimensional_reduction
#' @method RunUMAP default
#' @export
#'
RunUMAP.default <- function(
  object,
  reduction.key = 'UMAP_',
  assay = NULL,
  reduction.model = NULL,
  return.model = FALSE,
  umap.method = 'uwot',
  n.neighbors = 30L,
  n.components = 2L,
  metric = 'cosine',
  n.epochs = NULL,
  learning.rate = 1.0,
  min.dist = 0.3,
  spread = 1.0,
  set.op.mix.ratio = 1.0,
  local.connectivity = 1L,
  repulsion.strength = 1,
  negative.sample.rate = 5,
  a = NULL,
  b = NULL,
  uwot.sgd = FALSE,
  seed.use = 42,
  metric.kwds = NULL,
  angular.rp.forest = FALSE,
  densmap = FALSE,
  dens.lambda = 2,
  dens.frac = 0.3,
  dens.var.shift = 0.1,
  verbose = TRUE,
  ...
) {
  #(A1) 检查参数
  CheckDots(...)

  #(A2) 随机数种子参数非空，则设置它: UMAP 结果依赖随机数种子
  if (!is.null(x = seed.use)) {
    set.seed(seed = seed.use)
  }

  #(A3) 检查计算UMAP的方法
  # (B1)如果umap.method != 'umap-learn'，且 getOption('Seurat.warn.umap.uwot') 为 T，
  # 则显示一下通知: 转为调用R的 uwot 包了。
  # 下一次就不显示该通知了。
  if (umap.method != 'umap-learn' && getOption('Seurat.warn.umap.uwot', TRUE)) {
    warning(
      "The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric",
      "\nTo use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'",
      "\nThis message will be shown once per session",
      call. = FALSE,
      immediate. = TRUE
    )
    options(Seurat.warn.umap.uwot = FALSE)
  }

  #(B2) 如果是当前版本废弃的 umap.method='uwot-learn'， 则改为 "uwot"
  if (umap.method == 'uwot-learn') {
    warning("'uwot-learn' is deprecated. Set umap.method = 'uwot' and return.model = TRUE")
    umap.method <- "uwot"
    return.model <- TRUE
  }

  # (B3) 如果是 densmap=T 且 umap.method 不是 umap-learn，则警告并强转为 umap.method='umap-learn'
  if (densmap && umap.method != 'umap-learn'){
    warning("densmap is only supported by umap-learn method. Method is changed to 'umap-learn'")
    umap.method <- 'umap-learn'
  }

  # (B4) 如果返回模型，则强制使用 umap.method="uwot"
  if (return.model) {
    if (verbose) {
      message("UMAP will return its model")
    }
    umap.method = "uwot"
  }

  # (A4) 如果 obj 是 Neighbor 的实例(默认跳过)
  # 则改写为list:
  if (inherits(x = object, what = "Neighbor")) {
    object <- list( idx = Indices(object),
                    dist = Distances(object) )
  }

  # (A5) 如果 reduction.model 非空，则 umap.method="uwot-predict"(默认跳过)
  # UMAP 投影是什么？
  if (!is.null(x = reduction.model)) {
    if (verbose) {
      message("Running UMAP projection")
    }
    umap.method <- "uwot-predict"
  }



  #(A6) 根据 umap.method 的执行不同的处理，只能选择一个
  umap.output <- switch(
    EXPR = umap.method,

    #(B1) 执行py包 umap-learn (可选)
    'umap-learn' = {
      # 检查几个py包: umap, sklearn
      if (!py_module_available(module = 'umap')) {
        stop("Cannot find UMAP, please install through pip (e.g. pip install umap-learn).")
      }
      if (!py_module_available(module = 'sklearn')) {
        stop("Cannot find sklearn, please install through pip (e.g. pip install scikit-learn).")
      }

      # 设置随机数种子
      if (!is.null(x = seed.use)) {
        py_set_seed(seed = seed.use)
      }

      # n.epochs 默认为空，跳过
      if (typeof(x = n.epochs) == "double") {
        n.epochs <- as.integer(x = n.epochs)
      }

      # import umap, sklearn
      umap_import <- import(module = "umap", delay_load = TRUE)
      sklearn <- import("sklearn", delay_load = TRUE)

      # 检查版本号，如果是 densmap，则需要 umap-learn >=0.5.0
      if (densmap &&
          numeric_version(x = umap_import$pkg_resources$get_distribution("umap-learn")$version) <
          numeric_version(x = "0.5.0")) {
        stop("densmap is only supported by versions >= 0.5.0 of umap-learn. Upgrade umap-learn (e.g. pip install --upgrade umap-learn).")
      }

      # 随机数种子
      random.state <- sklearn$utils$check_random_state(seed = as.integer(x = seed.use))

      # umap 参数列表
      umap.args <- list(
        n_neighbors = as.integer(x = n.neighbors),
        n_components = as.integer(x = n.components),
        metric = metric,
        n_epochs = n.epochs,
        learning_rate = learning.rate,
        min_dist = min.dist,
        spread = spread,
        set_op_mix_ratio = set.op.mix.ratio,
        local_connectivity = local.connectivity,
        repulsion_strength = repulsion.strength,
        negative_sample_rate = negative.sample.rate,
        random_state = random.state,
        a = a,
        b = b,
        metric_kwds = metric.kwds,
        angular_rp_forest = angular.rp.forest,
        verbose = verbose
      )

      # 如果版本号大于 0.5.0 ，还可以加入 densmap 参数
      if (numeric_version(x = umap_import$pkg_resources$get_distribution("umap-learn")$version) >=
          numeric_version(x = "0.5.0")) {
        umap.args <- c(umap.args, list(
          densmap = densmap,
          dens_lambda = dens.lambda,
          dens_frac = dens.frac,
          dens_var_shift = dens.var.shift,
          output_dens = FALSE
        ))
      }
      # 执行umap: 参数、执行
      umap <- do.call(what = umap_import$UMAP, args = umap.args)
      umap$fit_transform(as.matrix(x = object))
    },

    # (B2) 默认，使用R包 uwot
    'uwot' = {
      # 如果obj是list (默认跳过)
      if (is.list(x = object)) {
        umap(
          X = NULL,
          nn_method = object,
          n_threads = nbrOfWorkers(),
          n_components = as.integer(x = n.components),
          metric = metric,
          n_epochs = n.epochs,
          learning_rate = learning.rate,
          min_dist = min.dist,
          spread = spread,
          set_op_mix_ratio = set.op.mix.ratio,
          local_connectivity = local.connectivity,
          repulsion_strength = repulsion.strength,
          negative_sample_rate = negative.sample.rate,
          a = a,
          b = b,
          fast_sgd = uwot.sgd,
          verbose = verbose,
          ret_model = return.model
        )
      # 如果obj 不是list (默认走这里)
      } else {
        umap(
          X = object, #矩阵: 前dims个PC列
          n_threads = nbrOfWorkers(), #线程数
          n_neighbors = as.integer(x = n.neighbors), #默认30
          n_components = as.integer(x = n.components), #默认2
          metric = metric, #默认 'cosine'
          n_epochs = n.epochs, #默认为空
          learning_rate = learning.rate, #默认1
          min_dist = min.dist, #默认0.3
          spread = spread, #默认1
          set_op_mix_ratio = set.op.mix.ratio, #1
          local_connectivity = local.connectivity, #1
          repulsion_strength = repulsion.strength, #1
          negative_sample_rate = negative.sample.rate, #5
          a = a, #空
          b = b, #空
          fast_sgd = uwot.sgd, #F
          verbose = verbose, #T
          ret_model = return.model #F
        )
      }

    },


    #(B3) 'uwot-predict' (默认跳过)：这个是干什么用的？ 这一段没看懂//todo
    'uwot-predict' = {
      # 如果指定 correlation 距离，则提醒 uwot R包没实现，改为了 cosine 距离。
      if (metric == 'correlation') {
        warning(
          "UWOT does not implement the correlation metric, using cosine instead",
          call. = FALSE,
          immediate. = TRUE
        )
        metric <- 'cosine'
      }

      # 如果 reduction.model 为空，或者 reduction.model 不是 DimReduc 的实例，则报错退出
      if (is.null(x = reduction.model) || !inherits(x = reduction.model, what = 'DimReduc')) {
        stop(
          "If running projection UMAP, please pass a DimReduc object with the model stored to reduction.model.",
          call. = FALSE
        )
      }
      
      # 模型
      model <- Misc(
        object = reduction.model,
        slot = "model"
      )

      # 如果长度为0，报错
      if (length(x = model) == 0) {
        stop(
          "The provided reduction.model does not have a model stored. Please try running umot-learn on the object first",
          call. = FALSE
        )
      }

      # 如果 obj 是list
      if (is.list(x = object)) {
      	# 看这个提示，是从参考系中查询坐标的: query and reference
        if (ncol(object$idx) != model$n_neighbors) {
          warning("Number of neighbors between query and reference ", 
          "is not equal to the number of neighbros within reference")
          model$n_neighbors <- ncol(object$idx)
        }
       umap_transform(
          X = NULL,
          nn_method = object,
          model = model,
          n_threads = nbrOfWorkers(),
          n_epochs = n.epochs,
          verbose = verbose
        )
      # 如果 obj 不是 list (dims 时走这里)
      } else {
        umap_transform(
          X = object,
          model = model,
          n_threads = nbrOfWorkers(),
          n_epochs = n.epochs,
          verbose = verbose
        )
      }

    },

    # 其他方法则报错
    stop("Unknown umap method: ", umap.method, call. = FALSE)
  )



  #(A7) 如果 return.model =T，则
  if (return.model) {
    umap.output$nn_index <- NULL # 这个是什么？
    umap.model <- umap.output #umap.model 新变量
    umap.output <- umap.output$embedding #umap.output 只保留嵌入坐标信息
  }

  # (A8) 添加列名: UMAP_1, UMAP_2
  colnames(x = umap.output) <- paste0(reduction.key, 1:ncol(x = umap.output))


  # (A9) 如果 obj 是 dist 的实例
  if (inherits(x = object, what = 'dist')) {
  	# 添加行名
    rownames(x = umap.output) <- attr(x = object, "Labels")
  } else if (is.list(x = object)) {
    rownames(x = umap.output) <- rownames(x = object$idx)
  } else {
    rownames(x = umap.output) <- rownames(x = object)
  }

  # (A10) 创建 DimReduc 对象
  umap.reduction <- CreateDimReducObject(
    embeddings = umap.output,
    key = reduction.key,
    assay = assay,
    global = TRUE
  )

  # (A11) 如果返回模型，保存在 misc@model 中
  if (return.model) {
    Misc(umap.reduction, slot = "model") <- umap.model
  }

  return(umap.reduction)
}







() todo
./seurat-4.1.0/R/dimensional_reduction.R:1446:RunUMAP.Graph <- function(
./seurat-4.1.0/R/dimensional_reduction.R:1547:RunUMAP.Neighbor <- function(




